<template>
  <div class="login-bk">
    <div class="login-title">
      <span>TYChat</span><br />
      <span>一起聆听世界的美好吧！</span>
    </div>
    <img class="loginBkImg" v-if="loginBkImg" :src="loginBkImg" alt="图片加载失败" />
    <div class="login-container">
      <p class="login-container__title">登录</p>
      <div class="login-container__form">
        <el-form ref="ruleFormRef" status-icon :model="ruleForm" :rules="rules">
          <el-form-item label="账号" prop="account">
            <el-input
              ref="accountRef"
              v-model="ruleForm.account"
              :maxlength="8"
              :disabled="isLoading"
              placeholder="请输入账号"
              @keypress.enter.prevent="focus($refs.passRef as any)"
            />
            <SvgIcon popper-class="input-icon" icon-class="user" />
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input
              ref="passRef"
              type="password"
              :disabled="isLoading"
              placeholder="请输入密码"
              v-model="ruleForm.password"
              autocomplete="off"
              :maxlength="10"
              @keypress.enter.prevent="submitForm(ruleFormRef)"
            />
            <SvgIcon popper-class="input-icon" icon-class="lock" />
          </el-form-item>
        </el-form>
      </div>
      <div class="login-container__footer">
        <el-button
          :disabled="isRequest || isLoading"
          type="primary"
          @click="submitForm(ruleFormRef)"
          :loading="isLoading"
          ><template #loading><Loading /></template
          >{{ isLoading ? "登录中" : "登录" }}</el-button
        >
        <div class="turn-register">
          <el-link :disabled="isRequest || isLoading" :underline="false" @click="turnPage"
            >没有账号？</el-link
          >
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import {
  ref,
  onBeforeMount,
  onBeforeUnmount,
  reactive,
  onMounted,
} from "@vue/runtime-core";
import { useRouter } from "vue-router";
import type { FormInstance, ElInput } from "element-plus";
import LoadingBar from "@/plugins/loadingBar";
import { ElMessage } from "element-plus";
import axios from "axios";
import Cookie from "@/plugins/cookie";
import { Base64 } from "js-base64";
import { usePinia } from "@/pinia/index";
import { useFriendPinia } from "@/pinia/friend";
import { storeToRefs } from "pinia";
import { useUserPinia } from "@/pinia/user";
import { useMessagePinia } from "@/pinia/messages";
import { useDynamicPinia } from "@/pinia/dynamic";

const router = useRouter();
const indexStore = usePinia();
const userStore = useUserPinia();
const { loginBkImg } = storeToRefs(indexStore);
const friendStore = useFriendPinia();
const messageStore = useMessagePinia();
const dynamicStore = useDynamicPinia();

/**
 * 该组件的根元素的高度
 */
let winHei = ref<string>("");

/**
 * 浏览器的可视高度改变则组件的根元素的高度也随之改变
 */
const handleToWid: () => void = (): void => {
  // 获取浏览器的可视高度
  const hei: number =
    globalThis.innerHeight ||
    document.body.clientHeight ||
    document.documentElement.clientHeight;
  if (hei <= 500) winHei.value = "500px";
  else winHei.value = `${hei}px`;
};
// 给浏览器添加监听窗口大小变化的事件
window.addEventListener("resize", handleToWid);

/**
 * 加载条组件
 */
const loBar: LoadingBar = new LoadingBar();
/**
 * 是否正在请求图片
 */
const isRequest = ref<boolean>(false);

onBeforeMount(() => {
  // 初始化组件根元素的高度
  handleToWid();
  if (!loginBkImg.value) {
    loBar.start();
    isRequest.value = true;
    indexStore
      .getLoginBkImg()
      .then((code: number) => {
        isRequest.value = false;
        if (code === 1) loBar.finsh();
        else {
          loBar.unMount();
          ElMessage.error("加载图片失败");
        }
      })
      .catch(() => {
        isRequest.value = false;
        loBar.unMount();
        router.push("/404");
      });
  }
});
// 组件卸载前移除该事件
onBeforeUnmount(() => window.removeEventListener("resize", handleToWid));

// 跳转至注册页面
const turnPage = (() => {
  let isLoading: boolean = false;
  return () => {
    if (isLoading) return;
    isLoading = true;
    loBar.start();
    Promise.all([
      // 请求验证码
      indexStore.getVerCode(),
      // 请求注册页面的背景图片
      indexStore.getRegisterBkImgs(),
    ])
      .then((codes: number[]) => {
        if (!codes.includes(0)) {
          loBar.finsh();
          router.push({ name: "register" });
        } else {
          loBar.unMount();
          ElMessage.error("加载失败");
        }
        isLoading = false;
      })
      .catch(() => {
        isLoading = false;
        loBar.unMount();
        ElMessage.error("加载失败");
      });
  };
})();

// 给密码输入框一个ref属性
const passRef = ref<typeof ElInput>();
// 给账号输入框一个ref属性
const accountRef = ref<typeof ElInput>();
// 给el-form标签一个ref属性
const ruleFormRef = ref<FormInstance>();
/**
 * 表单内的属性值
 */
const ruleForm = reactive<Pick<ValidateUser, "account" | "password">>({
  account: "",
  password: "",
});

// 密码输入框聚焦
const focus = (ele: typeof ElInput) => ele.focus();

onMounted(() => focus(accountRef.value!));

// 表单的验证
const validateInput = (
  title: string,
  count: number
): ((rule: any, value: string, callback: any) => void) => (
  rule: any,
  value: string,
  callback: any
): void => {
  if (!value) callback(new Error(`${title}不能为空`));
  else if (!value.match(/^[a-zA-Z0-9_\\.]{1,}$/g))
    callback(new Error(`${title}只能由字母、数字、小数点和下划线组成`));
  else if (value.length < count) callback(new Error(`${title}长度不能少于${count}位`));
  else callback();
};
/**
 * 表单校验规则
 */
const rules = reactive({
  account: [{ validator: validateInput("账号", 8), trigger: "change" }],
  password: [{ validator: validateInput("密码", 10), trigger: "change" }],
});

// 是否显示登录加载动画
const isLoading = ref<boolean>(false);

// 登录操作
const submitForm = (formEl: FormInstance | undefined) => {
  if (isRequest.value || !formEl) return;
  formEl.validate((valid) => {
    if (valid) {
      isLoading.value = true;
      axios
        .post("/api/user/login", {
          data: Base64.encode(
            JSON.stringify({ account: ruleForm.account, password: ruleForm.password })
          ),
        })
        .then((res) => {
          isLoading.value = false;
          const { data } = res;
          if (data.code === 1) {
            // 清空收到的加好友申请列表
            userStore.applicationList.size && userStore.applicationList.clear();
            // 清空历史记录
            indexStore.searchHistory.length && indexStore.searchHistory.splice(0);
            // 清除最新消息
            messageStore.chatList.size && messageStore.chatList.clear();
            // 初始化请求最新消息列表的状态(是否请求过)
            if (messageStore.isRequChatLisFinsh) messageStore.isRequChatLisFinsh = false;
            // 清除请求过的好友
            friendStore.friends.size && friendStore.friends.clear();
            // 初始化请求最新所有好友数据的状态(是否请求过)
            if (friendStore.isRequGetAllFriend) friendStore.isRequGetAllFriend = false;
            // 初始化请求通讯管理数据的状态(是否请求过)
            if (friendStore.isRequFriendsManage) friendStore.isRequFriendsManage = false;
            // 清除好友信息数据
            friendStore.friendsInfos.size && friendStore.friendsInfos.clear();
            // 清除通讯好友管理数据
            for (const item of friendStore.friendsManage.values()) {
              if (item.noGroups?.isRequest) item.noGroups.isRequest = false;
              if (item.noGroups?.friends.size) item.noGroups.friends.clear();
              if (item.groups?.size) item.groups.clear();
            }
            dynamicStore.dynamicDatas.value.size &&
              dynamicStore.dynamicDatas.value.clear();
            dynamicStore.dynamicDatas.isHasNew = false;
            dynamicStore.dynamicDatas.isRequest = false;
            dynamicStore.dynamicDatas.isReload = false;
            dynamicStore.mySelfDynamicDatas.value.size &&
              dynamicStore.mySelfDynamicDatas.value.clear();
            dynamicStore.mySelfDynamicDatas.isRequest = false;
            dynamicStore.mySelfDynamicDatas.isReload = false;
            Cookie.setCookie({
              key: "token",
              value: data.data.token,
            });
            userStore.isFirst = data.data.isFirst;
            // 如果用户是第一次登录的话
            if (userStore.isFirst) router.replace({ name: "setUserInfo" });
            else router.push("/");
          } else {
            ElMessage.error(`${data.msg}`);
            focus(accountRef.value!);
          }
        })
        .catch(() => {
          isLoading.value = false;
          ElMessage.error("登录失败，请在尝试一次");
          focus(accountRef.value!);
        });
    }
  });
};
</script>

<style lang="scss" scoped>
.login {
  &-bk {
    height: v-bind(winHei);
    min-width: 900px;
    overflow: hidden;
    position: relative;

    .loginBkImg {
      @include setWidHei(100%, 100%);
      object-fit: cover;
    }
  }

  &-title {
    position: absolute;
    top: 10%;
    left: 8%;
    color: #fff;

    span {
      &:first-child {
        font: {
          size: 3rem;
          weight: bold;
          family: "Courier New", Courier, monospace;
        }
      }

      &:last-child {
        display: inline-block;
        margin: 2px;
        letter-spacing: 1px;
        font: 1.7rem FZShuTi, STHupo, STCaiyun;
      }
    }
  }

  &-container {
    position: absolute;
    top: 25%;
    right: 15%;
    @include card(400px, 300px, 5px);

    &__title {
      margin: 0;
      text-align: center;
      font-size: 20px;
    }

    &__footer {
      margin: 30px auto;
      width: 285px;

      :deep(.el-button) {
        width: 285px;
      }

      .turn-register {
        margin-top: 20px;
        text-align: right;
      }
    }

    &__form {
      margin: 25px auto;
      width: 285px;
      color: rgba(248, 246, 238, 0.667);

      :deep(.el-input__inner) {
        padding-left: 28px;
      }

      :deep(.el-form-item) {
        margin-bottom: 23px;
      }
    }
  }
}
</style>
